package com.eduagent.xwqeduagent.api.OneSentenceReprint.api;

import com.google.gson.Gson;
import lombok.Data;
import okhttp3.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * 声音复刻(音频合成)服务
 */
@Service
public class VoiceCloneService {

    @Value("${xfyun.appid}")
    private String APPID;

    @Value("${xfyun.apikey}")
    private String APIKEY;

    @Value("${xfyun.apisecret}")
    private String APISECRET;
    
    private static final String HOST_URL = "http://cn-huabei-1.xf-yun.com/v1/private/voice_clone";
    private static final Gson GSON = new Gson();
    private static final OkHttpClient HTTP_CLIENT = new OkHttpClient.Builder()
            .connectTimeout(60, TimeUnit.SECONDS)
            .writeTimeout(60, TimeUnit.SECONDS)
            .readTimeout(60, TimeUnit.SECONDS)
            .build();

    /**
     * 进行音频合成
     * @param request 合成请求参数
     * @param outputFilePath 输出文件路径
     * @return 合成结果
     * @throws Exception 请求异常时抛出
     */
    public CloneResult synthesizeAudio(CloneRequest request, String outputFilePath) throws Exception {
        // 校验必要参数
        if (request.getResId() == null || request.getResId().isEmpty()) {
            throw new IllegalArgumentException("音色ID不能为空");
        }
        if (request.getText() == null || request.getText().isEmpty()) {
            throw new IllegalArgumentException("合成文本不能为空");
        }
        
        // 生成鉴权URL
        String authUrl = getAuthUrl(HOST_URL, APPID, APISECRET);
        String wsUrl = authUrl.replace("http://", "ws://").replace("https://", "wss://");
        
        // 创建结果对象及同步锁
        CloneResult result = new CloneResult();
        CountDownLatch latch = new CountDownLatch(1);
        
        // 创建WebSocket连接
        Request wsRequest = new Request.Builder().url(wsUrl).build();
        WebSocketListener listener = new CloneWebSocketListener(request, outputFilePath, result, latch);
        WebSocket webSocket = HTTP_CLIENT.newWebSocket(wsRequest, listener);
        
        // 等待合成完成
        boolean completed = latch.await(60, TimeUnit.SECONDS);
        if (!completed) {
            webSocket.close(1000, "timeout");
            throw new RuntimeException("音频合成超时");
        }
        
        return result;
    }
    
    /**
     * WebSocket监听器
     */
    private class CloneWebSocketListener extends WebSocketListener {
        private final CloneRequest request;
        private final String outputFilePath;
        private final CloneResult result;
        private final CountDownLatch latch;
        private boolean hasError = false;

        public CloneWebSocketListener(CloneRequest request, String outputFilePath, CloneResult result, CountDownLatch latch) {
            this.request = request;
            this.outputFilePath = outputFilePath;
            this.result = result;
            this.latch = latch;
        }

        @Override
        public void onOpen(WebSocket webSocket, Response response) {
            try {
                // 构建请求JSON
                Map<String, Object> requestJson = new HashMap<>();
                
                // header参数
                Map<String, Object> header = new HashMap<>();
                header.put("app_id", APPID);
                header.put("res_id", request.getResId());
                header.put("status", 2);  // 一次性传输文本
                requestJson.put("header", header);
                
                // parameter参数
                Map<String, Object> parameter = new HashMap<>();
                Map<String, Object> tts = new HashMap<>();
                tts.put("vcn", "x5_clone");
                tts.put("volume", request.getVolume() != null ? request.getVolume() : 50);
                tts.put("rhy", request.getRhy() != null ? request.getRhy() : 0);
                tts.put("pybuffer", request.getPybuffer() != null ? request.getPybuffer() : 1);
                tts.put("speed", request.getSpeed() != null ? request.getSpeed() : 50);
                tts.put("pitch", request.getPitch() != null ? request.getPitch() : 50);
                tts.put("LanguageID", request.getLanguageId() != null ? request.getLanguageId() : 0);
                
                Map<String, Object> audio = new HashMap<>();
                audio.put("encoding", request.getEncoding() != null ? request.getEncoding() : "lame");
                audio.put("sample_rate", request.getSampleRate() != null ? request.getSampleRate() : 16000);
                tts.put("audio", audio);
                
                Map<String, Object> pybuf = new HashMap<>();
                pybuf.put("encoding", "utf8");
                pybuf.put("compress", "raw");
                pybuf.put("format", "plain");
                tts.put("pybuf", pybuf);
                
                parameter.put("tts", tts);
                requestJson.put("parameter", parameter);
                
                // payload参数
                Map<String, Object> payload = new HashMap<>();
                Map<String, Object> text = new HashMap<>();
                text.put("encoding", "utf8");
                text.put("compress", "raw");
                text.put("format", "plain");
                text.put("status", 2);
                text.put("seq", 0);
                text.put("text", Base64.getEncoder().encodeToString(request.getText().getBytes(StandardCharsets.UTF_8)));
                payload.put("text", text);
                requestJson.put("payload", payload);
                
                // 发送请求
                webSocket.send(GSON.toJson(requestJson));
            } catch (Exception e) {
                result.setSuccess(false);
                result.setMessage("构建请求失败: " + e.getMessage());
                latch.countDown();
            }
        }

        @Override
        public void onMessage(WebSocket webSocket, String text) {
            try {
                JsonResponse response = GSON.fromJson(text, JsonResponse.class);
                
                // 检查响应状态
                if (response.header.code != 0) {
                    result.setSuccess(false);
                    result.setMessage("合成失败，错误码: " + response.header.code + ", 错误信息: " + response.header.message);
                    result.setSid(response.header.sid);
                    hasError = true;
                    latch.countDown();
                    return;
                }
                
                // 解析响应中的音频数据
                if (response.payload != null && response.payload.audio != null && response.payload.audio.audio != null) {
                    String audioBase64 = response.payload.audio.audio;
                    byte[] audioData = Base64.getDecoder().decode(audioBase64);
                    
                    // 将音频数据写入文件
                    try (FileOutputStream fos = new FileOutputStream(outputFilePath, result.isAppendFile())) {
                        fos.write(audioData);
                        result.setAppendFile(true);  // 标记为追加模式
                    } catch (IOException e) {
                        result.setSuccess(false);
                        result.setMessage("写入音频文件失败: " + e.getMessage());
                        latch.countDown();
                    }
                }
                
                // 提取音素标注信息
                if (response.payload != null && response.payload.pybuf != null && response.payload.pybuf.text != null) {
                    String pybufBase64 = response.payload.pybuf.text;
                    if (!pybufBase64.isEmpty()) {
                        byte[] pybufData = Base64.getDecoder().decode(pybufBase64);
                        String pybufText = new String(pybufData, StandardCharsets.UTF_8);
                        result.setPyBufText(pybufText);
                    }
                }
                
                // 检查是否完成
                if (response.header.status == 2) {
                    result.setSuccess(!hasError);
                    result.setSid(response.header.sid);
                    if (!hasError) {
                        result.setMessage("音频合成成功");
                    }
                    latch.countDown();
                }
            } catch (Exception e) {
                result.setSuccess(false);
                result.setMessage("处理响应失败: " + e.getMessage());
                latch.countDown();
            }
        }

        @Override
        public void onFailure(WebSocket webSocket, Throwable t, Response response) {
            result.setSuccess(false);
            result.setMessage("WebSocket连接失败: " + t.getMessage());
            latch.countDown();
        }

        @Override
        public void onClosed(WebSocket webSocket, int code, String reason) {
            if (!result.isSuccess() && result.getMessage() == null) {
                result.setMessage("WebSocket连接已关闭: " + reason);
            }
            if (latch.getCount() > 0) {
                latch.countDown();
            }
        }
    }
    
    /**
     * 生成鉴权URL
     */
    private String getAuthUrl(String hostUrl, String appid, String apiSecret) throws Exception {
        URL url = new URL(hostUrl);
        // 时间
        SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
        format.setTimeZone(TimeZone.getTimeZone("GMT"));
        String date = format.format(new Date());
        // signature的原始字段
        String preStr = "host: " + url.getHost() + "\n" +
                "date: " + date + "\n" +
                "GET " + url.getPath() + " HTTP/1.1";
        // SHA256加密
        Mac mac = Mac.getInstance("hmacsha256");
        SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(StandardCharsets.UTF_8), "hmacsha256");
        mac.init(spec);
        byte[] hexDigits = mac.doFinal(preStr.getBytes(StandardCharsets.UTF_8));
        // Base64加密
        String signature = Base64.getEncoder().encodeToString(hexDigits);
        // authorization的原始字段
        String authorization = String.format("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"", 
                APIKEY, "hmac-sha256", "host date request-line", signature);
        // 拼接地址
        HttpUrl httpUrl = Objects.requireNonNull(HttpUrl.parse("https://" + url.getHost() + url.getPath())).newBuilder().
                addQueryParameter("authorization", Base64.getEncoder().encodeToString(authorization.getBytes(StandardCharsets.UTF_8))).
                addQueryParameter("date", date).
                addQueryParameter("host", url.getHost()).
                build();
        
        return httpUrl.toString();
    }
    
    /**
     * 请求参数类
     */
    @Data
    public static class CloneRequest {
        private String resId;         // 音色ID，训练得到的音色id
        private String text;          // 要合成的文本内容
        private Integer languageId;   // 语种ID：中文0，英语1，日语2，韩语3，俄语4
        private Integer volume;       // 音量：0-100，默认50
        private Integer rhy;          // 是否返回音素信息/拼音标注，默认0
        private Integer pybuffer;     // 输出音素时长信息，默认1
        private Integer speed;        // 语速：0-100，默认50
        private Integer pitch;        // 语调：0-100，默认50
        private String encoding;      // 音频编码，默认lame
        private Integer sampleRate;   // 采样率，默认16000
    }
    
    /**
     * 响应结果类
     */
    @Data
    public static class CloneResult {
        private boolean success = true;   // 是否成功
        private String message;           // 消息
        private String sid;               // 会话ID
        private String pyBufText;         // 音素标注文本
        private boolean appendFile = false; // 是否以追加方式写入文件
    }
    
    /**
     * JSON响应解析类
     */
    private static class JsonResponse {
        Header header;
        Payload payload;
    }
    
    private static class Header {
        int code;
        String message;
        String sid;
        int status;
    }
    
    private static class Payload {
        Audio audio;
        PyBuf pybuf;
    }
    
    private static class Audio {
        int status;
        String audio;
    }
    
    private static class PyBuf {
        int status;
        int seq;
        String text;
    }
} 